<template>
  <div class="about height100" id="box">
    <div class="list area-left" id="sider-left" ></div>
    <div id="container"></div>
    <div class="toor">
      <el-button-group>
        <el-button @click="change('onUndo')" :disabled="!canUndo" >撤消</el-button>
        <el-button @click="change('onRedo')" :disabled="!canRedo">还原</el-button>
      </el-button-group>
    </div>
    <div id="sider-right">
      <el-tabs v-model="siderRight" >
        <el-tab-pane label="数据源" name="data" v-if="configs.includes('data')">
          <el-form>
<!--          <el-divider content-position="left">查询</el-divider>-->
<!--            <el-form-item label="接口">-->
<!--              <el-input style="width: 210px;" v-model.trim="cell.compareField" @input="configChange('node')"></el-input>-->
<!--            </el-form-item>-->
<!--            <el-form-item label="参数">-->
<!--              <el-input style="width: 210px;" v-model.trim="cell.compareField" @input="configChange('node')"></el-input>-->
<!--            </el-form-item>-->
          <el-divider content-position="left">筛选</el-divider>
            <el-form-item label="字段">
              <el-input style="width: 210px;" v-model.trim="cell.compareField" @input="configChange('node')"></el-input>
            </el-form-item>
            <el-form-item label="比较">
              <el-select style="width: 210px;" v-model="cell.compareType" placeholder="请选择" @change="configChange('node')">
                <el-option
                    v-for="item in cell.compareOpt"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                </el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="值">
              <el-input-number style="width: 225px;padding-left: 15px;" v-model="cell.compareVal" @change="configChange('node')" controls-position="right"></el-input-number>
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <el-tab-pane label="算子" name="math" v-if="configs.includes('math')">
          <el-divider content-position="left">参数</el-divider>
          <el-table :data="tableData" border>
            <el-table-column prop="arg" label="参数(X/Y)" width="100"></el-table-column>
            <el-table-column label="权重(w)">
              <template slot-scope="scope">
                <el-input-number v-model="scope.row.weight" :min="1" @change="configChange('node')" controls-position="right"></el-input-number>
              </template>
            </el-table-column>
          </el-table>
          <el-divider content-position="left">运算</el-divider>
          <el-table :data="computeData" border>
            <el-table-column prop="compIcon" label="运算符"></el-table-column>
            <el-table-column prop="compute" label="运算"></el-table-column>
            <el-table-column prop="compExpression" label="表达式"></el-table-column>
          </el-table>
        </el-tab-pane>
        <el-tab-pane label="线条" name="line" v-if="configs.includes('line')">
          <el-form>
            <el-form-item label="宽度">
              <el-slider v-model="cell.lineWidth" :min="1" :max="5" @change="configChange('line')"></el-slider>
            </el-form-item>
            <el-form-item label="颜色">
              <el-color-picker style="width: 210px;" v-model="cell.lineColor" @change="configChange('line')"></el-color-picker>
            </el-form-item>
            <el-form-item label="线条">
              <el-select v-model="cell.lineType" @change="configChange('line')">
                <el-option label="直线" value="normal"></el-option>
                <el-option label="曲线" value="smooth"></el-option>
              </el-select>
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <el-tab-pane label="节点" name="node" v-if="configs.includes('node')">
          <el-form>
            <el-form-item label="宽度">
              <el-slider v-model="cell.nodeWidth" :min="1" :max="5" @change="configChange('node')"></el-slider>
            </el-form-item>
            <el-form-item label="边框">
              <el-color-picker style="width: 210px;" v-model="cell.nodeColor" @change="configChange('node')"></el-color-picker>
            </el-form-item>
            <el-form-item label="填充">
              <el-color-picker style="width: 210px;" v-model="cell.nodeFill" @change="configChange('node')"></el-color-picker>
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <el-tab-pane label="文本" name="text" v-if="configs.includes('text')">
          <el-form>
            <el-form-item label="文本">
              <el-input style="width: 210px;" v-model.trim="cell.textText" @input="configChange('node')"></el-input>
            </el-form-item>
            <el-form-item label="颜色">
              <el-color-picker style="width: 210px;" v-model="cell.textColor" @change="configChange('node')"></el-color-picker>
            </el-form-item>
            <el-form-item label="字体">
              <el-slider v-model="cell.textSize" :min="12" :max="18" @change="configChange('node')"></el-slider>
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <el-tab-pane label="网格" name="grid" v-if="configs.includes('grid')">网格</el-tab-pane>
        <el-tab-pane label="背景" name="bg" v-if="configs.includes('bg')">背景</el-tab-pane>
        <el-tab-pane label="结果" name="result" v-if="configs.includes('result')">
          <el-button @click="change('get')">获取结果</el-button>  {{result}}
        </el-tab-pane>

      </el-tabs>
    </div>
  </div>
</template>
<script>
import { Graph,Addon,Shape } from '@antv/x6';
import { sider,data,compute,result } from "../../public/config";

const { Stencil } = Addon;
const { Rect, Circle,Cylinder } = Shape;
import { treeToArray } from "../util";

export default {
  data(){
    return {
      jData:[
        {id:1,get:12},{id:2,get:16},{id:3,get:2},{id:4,get:50},{id:5,get:10},
      ],
      result:null,
      graph: null,//画布对象
      stencil:null,//左侧子类栏
      dataSource:[
        {
          width: 60,
          height: 60,
          innerText: '任务数据',
          compareField: 'get',
          compareType: 0,
          compareVal: 10
        },
        {
          width: 60,
          height: 60,
          innerText: '突发事件',
          compareField: 'get',
          compareType: 0,
          compareVal: 20
        },
        {
          width: 60,
          height: 60,
          innerText: '员工工资',
          compareField: 'get',
          compareType: 0,
          compareVal: 20
        },
        {
          width: 60,
          height: 60,
          innerText: '员工奖金',
          compareField: 'get',
          compareType: 0,
          compareVal: 20
        }
      ],
      computes: [
        {
          width: 70,
          height: 40,
          innerText: 'X + Y',
          compute: '+',
          weightX: 1,
          weightY: 1
        },
        {
          width: 70,
          height: 40,
          innerText: 'X - Y',
          compute: '-',
          weightX: 1,
          weightY: 1
        },
        {
          width: 70,
          height: 40,
          innerText: 'X * Y',
          compute: '*',
          weightX: 1,
          weightY: 1
        },
        {
          width: 70,
          height: 40,
          innerText: 'X / Y',
          compute: '/',
          weightX: 1,
          weightY: 1
        }
      ],
      configs:['grid','bg'],//右侧默认工具栏tab页
      siderRight:'grid',//右侧工具栏
      toors:[
        {label:'撤销',icon:'el-icon-refresh-left'},
        {label: '前进',icon: 'el-icon-refresh-right'}
      ],
      canUndo:false,
      canRedo:false,
      cell:{//当前选中对象的配置
        lineWidth:1,
        lineColor:'#409EFF',
        lineType:'normal',
        nodeWidth:2,
        nodeColor:'#000',
        nodeFill:'#000',
        textText:'',
        textColor:'#000',
        textSize:'12',
        compareField: 'get',
        compareType: 0,
        compareVal: 10,
        compareOpt:[
          {value:0,label:'大于'},{value:1,label:'大于等于'},{value:2,label:'小于'},
          {value:3,label:'小于等于'},{value:4,label:'等于'}
        ],
      },
      curnode:null,//当前选中对象
      tableData:[],
      computeData:[],
      resTree:[],//结果树
    }
  },
  mounted() {
    this.init();
  },
  methods:{
    init(){
      this.graph = new Graph({
        container: document.getElementById('container'),
        //回退
        history: true,
        //键盘
        keyboard: true,
        selecting: {
          enabled: true,
          showNodeSelectionBox: true,
        },
        clipboard: {
          enabled: true,
        },
        // background: {
        //   color: '#f5f5f5',
        // },
        snapline:true,
        //网格线
        grid: true,
        //滚动窗口
        scroller: {
          enabled: true,
          pageVisible: true,
          pageBreak: true,
          pannable: true,
        },
        //滚动放大
        mousewheel: {
          enabled: true,
          modifiers: ['ctrl', 'meta'],
          minScale: 0.5,
          maxScale: 2,
        },
        connecting: {
          snap: true,
          allowBlank: false,
          allowLoop: false,
          highlight: true,
          sourceAnchor: {
            name: 'bottom',
          },
          targetAnchor: {
            name: 'center',
          },
          // connectionPoint: 'anchor',
          connector:'smooth', //连接线的类型
          createEdge:() => {
            //连接线的样式 拖动连接时连接线的样式
            return new Shape.Edge({
              attrs: {
                line: {
                  strokeDasharray: "5 5", //连接虚线
                  stroke: "#808080",
                  strokeWidth: 1,
                }
              }
            });
          },
          validateMagnet({ magnet }) {
            return magnet.getAttribute('port-group') !== 'in';
          },
          validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
            // 只能从输出链接桩创建连接
            if (!sourceMagnet || sourceMagnet.getAttribute('port-group') === 'in') {
              return false;
            }

            // 只能连接到输入链接桩
            if (!targetMagnet || targetMagnet.getAttribute('port-group') !== 'in') {
              return false;
            }

            // 判断目标链接桩是否可连接
            const portId = targetMagnet.getAttribute('port');
            const node = targetView.cell;
            const port = node.getPort(portId);
            if (port && port.connected) {
              return false;
            }

            return true;
          },
        },
      });
      this.addEvent();
      this.addKey();
      this.initSider();
    },
    addEvent(){
      let graph = this.graph;
      graph.history.on('change', () => {
        this.canUndo = graph.history.canUndo();
        this.canRedo = graph.history.canRedo();
      })

      //连接线结束事件
      graph.on('edge:connected', (args) => {

        const edge = args.edge;
        console.log(edge, edge.source,edge.target)
        const node = args.currentCell;
        const elem = args.currentMagnet;
        const portId = elem.getAttribute('port');
        // 触发 port 重新渲染
        node.setPortProp(portId, 'connected', true);
        node.setPortProp(portId, 'source', edge.source);
        // 更新连线样式
        edge.attr({
          line: {
            strokeDasharray: "",//实线
            stroke: "#808080",
            strokeWidth: 2,
          },
        })
        edge.setConnector('smooth');
      })

      // //节点右键事件
      // graph.on('node:contextmenu', ({ cell, view }) => {
      //   const cellType = cell.store.data.customizeType;
      //   if(cellType === 'form') return;
      //   const oldText = cell.attr('text/text');
      //   const cellPos = cell.position();
      //   const cellSize = cell.size();
      //   this.graph.addNode(new Rect({
      //     x:cellPos.x + cellSize.width + 10,
      //     y:cellPos.y,
      //     customizeType: 'form', //自定义属性 用于后续判断是否添加节点
      //     width: 150,
      //     height: 200,
      //     attrs: {
      //       rect: {  stroke: '#ced4de', strokeWidth: 1 },
      //       text: { text: 'X+Y+Z', fill: 'red' },
      //     },
      //   }))
      // })

      //边点击事件
      graph.on('edge:click', ({ e, x, y, cell, view }) => {
        this.curnode = cell;
        const { data } = cell.store;
        const lineType = data.connector ? data.connector.name : 'smooth';
        const lineWidth = data.attrs.line.strokeWidth;
        const lineColor = data.attrs.line.stroke;
        this.configs = ['line'];
        this.siderRight = 'line';
        this.cell.lineType = lineType;
        this.cell.lineWidth = lineWidth;
        this.cell.lineColor = lineColor;
      })

      graph.on('edge:mouseenter', ({ cell }) => {
        cell.addTools(
            [
              {
                name: 'button-remove',
                args: { distance: -30  }, //删除按钮的位置
              },
            ],
            'onhover' //hover时出现
        )
      })

      graph.on('edge:mouseleave', ({ cell }) => {
        if (cell.hasTools('onhover')) {
          cell.removeTools();
        }
      })

      graph.on('edge:removed', ({ edge, index, options }) => {
        const target = edge.target; //连接的node节点
        const nodeView = graph.findViewByCell(target.cell);
        if(nodeView){
          //将原来的node节点改变连接状态
          nodeView.cell.setPortProp(target.port, 'connected', false);
          nodeView.cell.setPortProp(target.port, 'source', null);
        }
      })

      //节点点击事件
      graph.on('node:click', ({ e, x, y, cell, view }) => {
        console.log(cell)
        this.curnode = cell;
        if(cell.attr('result') === 'result'){
          this.configs = ['result'];
          this.siderRight = 'result';
          return
        }
        const { data } = cell.store;
        const nodeType = data.shape;
        const nodeWidth = cell.attr(`${nodeType}/strokeWidth`);
        const nodeColor = cell.attr(`${nodeType}/stroke`);
        const nodeFill = cell.attr(`${nodeType}/fill`);
        const { fill, fontSize,text } = cell.attr('text');
        this.configs = ['node','text'];
        if(nodeType === 'circle'){
          const { compareField,compareType,compareVal } = cell.attr('field');
          this.configs.push('data');
          this.siderRight = 'data';
          this.cell.compareField = compareField;
          this.cell.compareType = compareType;
          this.cell.compareVal = compareVal;
        }else if(nodeType === 'rect'){
          const ports = cell.port.getPorts().filter(item=>item.group==='in');
          const compIcon = cell.attr('compute');
          this.configs.push('math');
          this.siderRight = 'math';
          let compute;
          let compExpression;
          if(compIcon === '+'){
            compute = '加法';
            compExpression = '(X*Xw)+(Y*Yw)';
          }else if(compIcon === '-'){
            compute = '减法';
            compExpression = '(X*Xw)-(Y*Yw)';
          }else if(compIcon === '*'){
            compute = '乘法';
            compExpression = '(X*Xw)*(Y*Yw)';
          }else if(compIcon === '/'){
            compute = '除法';
            compExpression = '(X*Xw)/(Y*Yw)';
          }
          this.computeData = [{compIcon,compute,compExpression}];
          this.tableData = [];
          ports.forEach((item,index)=>{
            this.tableData.push({arg:(index?'Y':'X'),weight:item.weight,id:item.id});
          })

        }
        this.cell.nodeWidth = nodeWidth;
        this.cell.nodeColor = nodeColor;
        this.cell.nodeFill = nodeFill;
        this.cell.textText = text;
        this.cell.textColor = fill;
        this.cell.textSize = fontSize;
      })

      graph.on('node:mouseenter', ({ node }) => {
        const type = node.store.data.shape;
        const { width,height } = node.store.data.size;
          node.addTools({
            name: 'button-remove',
            args: {
              x: type === 'rect' ? width : width - 2,
              y: type === 'rect' ? 2 : 4 ,
            }
          })
      })

      graph.on('node:mouseleave', ({ node }) => {
          node.removeTools();
      })

      //网格点击事件
      graph.on('blank:click', ({ e, x, y, }) => {
        this.configs = ['grid','bg'];
        this.siderRight = 'grid';
      })
    },
    addKey(){
      //添加快捷键操作
      this.graph.bindKey('ctrl+c', () => {
        const cells = this.graph.getSelectedCells();
        if (cells.length) {
          this.graph.copy(cells);
        }
        return false;
      })

      this.graph.bindKey('ctrl+v', () => {
        if (!this.graph.isClipboardEmpty()) {
          const cells = this.graph.paste({ offset: 32 });
          this.graph.cleanSelection();
          this.graph.select(cells);
        }
        return false;
      })

      this.graph.bindKey('ctrl+z', () => {
        this.graph.undo();
      })

      this.graph.bindKey('ctrl+y', () => {
        this.graph.redo();
      })
    },
    change(type){
      //获取结果
      if(type === 'get'){
        const cell = this.curnode;
        //判断当前结果是否已经连接
        const port = cell.getPortAt(0);
        let parent = {
          cell:null,
          port:'result',
          parentId:null,
          children:[]
        };
        if(port.connected){
          const source = this.graph.getCellById(cell.getPortAt(0).source.cell);
          //  判断来源是否是数据源
          //  如果是就执行运算
          if(source.shape === 'circle'){
            //获取数据
            alert('当前结果：'+this.computeDataFrom(cell.getPortAt(0).source.cell));
          }
          //  如果不是来源就是算法
          else{
            this.createResTree(cell.id,parent,null);
            this.computeTree(parent.children[0]);
            while (parent.children[0].result===undefined){
              this.computeRes(parent.children[0])
            }
            alert(parent.children[0].result);
          }
        }
        return
      }

      //撤销 还原
      let graph = this.graph;
      type === 'onUndo' ? graph.history.undo() : graph.history.redo();
    },
    initSider(){
      this.stencil = new Stencil(Object.assign({target:this.graph},sider));
      document.getElementById('sider-left').appendChild(this.stencil.container);
      const dataSource = [];//数据源
      this.dataSource.forEach(item=>{
        dataSource.push(new Circle(data(item.width,item.height,item.innerText,item.compareField,item.compareType,item.compareVal)));
      })
      const computes = [];//算子
      this.computes.forEach(item=>{
        console.log(compute(item.width,item.height,item.innerText,item.compute,item.weightX,item.weightY))
        computes.push(new Rect(compute(item.width,item.height,item.innerText,item.compute,item.weightX,item.weightY)));
      })

      this.stencil.load(dataSource, 'dataSource');
      this.stencil.load(computes, 'compute');
      this.stencil.load([new Rect(result(70,40,'输出结果'))],'result');
     },
    configChange(type){
      const cell = this.curnode;
      const {
        lineColor,lineWidth,lineType,nodeColor,nodeWidth,nodeFill,textText,textSize,textColor,
        compareField,compareType,compareVal
      } = this.cell;
      if(type === 'line'){
        cell.attr({
          line: {
            stroke: lineColor,
            strokeWidth: lineWidth,
          },
        })
        cell.setConnector(lineType);
      }else if(type === 'node'){
        const nodeType = cell.store.data.shape;
        const portProp = this.tableData;
        if(nodeType === 'rect'){ //算子
          cell.attr({
            rect:{ fill: nodeFill, stroke: nodeColor, strokeWidth: nodeWidth},
            text:{ fill: textColor, fontSize: textSize, text: textText },
          })
          portProp.forEach(item=>{
            cell.setPortProp(item.id,'weight',item.weight)
          })
        }else if(nodeType === 'circle'){ //数据源
          cell.attr({
            circle:{ fill: nodeFill, stroke: nodeColor, strokeWidth: nodeWidth },
            text:{ fill: textColor, fontSize: textSize, text: textText },
            field: { compareField,compareType,compareVal }
          })
        }
      }
    },
    createResTree(id,res,parentId){
      const cell = this.graph.getCellById(id);
      const ports = cell.port.getPorts().filter(i=>i.group==='in');

      //先判断是否都连接了
      if(!ports.every(i=>i.connected)){
        alert('请正确连接流程')
        return false;
      }
      res.parentId = parentId;
      res.cell = id;
      ports.forEach(item=>{
        item.source.children = [];
        this.createResTree(item.source.cell,item.source,id)
        res.children.push(item.source);
      })
    },
    computeTree(resTree){
      if(resTree.port === 'result'){
        for(var i=0;i<resTree.children.length;i++){
          if(resTree.children[i].port !== 'dataFrom'){
            this.computeTree(resTree.children[i]);
          }else{
            resTree['result'+i] = this.computeDataFrom(resTree.children[i].cell);
          }
        }
      }
    },
    // computeResult(resTree){
    //   if(resTree.children.every(i=>i.port==='dataFrom')){
    //     resTree.result = this.computeComp(resTree.cell,resTree.result0,resTree.result1);
    //   }else{
    //     for(var i=0;i<resTree.children.length;i++){
    //       if(resTree.children[i].port!=='dataFrom'){
    //         this.computeResult(resTree.children[i]);
    //       }
    //     }
    //   }
    // },
  //  计算数据源
    computeDataFrom(id){
      const cell = this.graph.getCellById(id);
      const resultData = this.jData;
      const { compareField,compareType,compareVal } = cell.attr('field');
      let resVal = 0;
      switch (compareType) {
        case 0:
          resultData.forEach(item=>{
            if(item[compareField] > compareVal){
              resVal += item[compareField];
            }
          })
          break;
        case 1:
          resultData.forEach(item=>{
            if(item[compareField] > compareVal || item[compareField] === compareVal){
              resVal += item[compareField];
            }
          })
          break;
        case 2:
          resultData.forEach(item=>{
            if(item[compareField] < compareVal){
              resVal += item[compareField];
            }
          })
          break;
        case 3:
          resultData.forEach(item=>{
            if(item[compareField] < compareVal || item[compareField] === compareVal){
              resVal += item[compareField];
            }
          })
          break;
        default:
          resultData.forEach(item=>{
            if(item[compareField] === compareVal){
              resVal += item[compareField];
            }
          })
          break;
      }
      return resVal;
    },
    //计算算子
    computeComp(id,x,y){
      const cell = this.graph.getCellById(id);
      const comp = cell.attr('compute');
      const Xwei = cell.port.getPorts()[0].weight;
      const Ywei = cell.port.getPorts()[1].weight;
      let res;
      switch (comp) {
        case '+':
          res = (x*Xwei) + (y*Ywei);
          break;
        case '-':
          res = (x*Xwei) - (y*Ywei);
          break;
        case '*':
          res = (x*Xwei) * (y*Ywei);
          break;
        default:
          res = (x*Xwei) / (y*Ywei);
      }
      return res;
    },
  //  计算结果
    computeRes(tree){
      //如果tree的result0 === undefiend
      if(tree.result0 === undefined){
        if(tree.children[0].result !== undefined){
          tree.result0 = tree.children[0].result;
        }else{
          this.computeRes(tree.children[0]);
        }
      }
      //如果tree的result1 === undefined
      else if(tree.result1 === undefined){
        if(tree.children[1].result !== undefined){
          tree.result1 = tree.children[1].result;
        }else{
          this.computeRes(tree.children[1]);
        }
      }
      //否则
      else{
        tree.result = this.computeComp(tree.cell,tree.result0,tree.result1);
      }
    },

  }
}
</script>
<style lang="scss" scoped>
.about{
  display: flex;
  .list{
    width: 220px;
    height: 100%;
    overflow-y: auto;
  }
  #container{
    position: relative;
    flex: 1;
  }
    .toor{
      position: fixed;
      top: 40px;
      left: 220px;
      z-index: 1000;
      padding: 5px 10px;
      background-color: #fff;
    }
  #sider-right{
    width: 300px;
    height: 100%;
    overflow-y: auto;
    padding: 0 20px;
    .el-tab-pane{
      padding: 10px 0;
    }
    /deep/.el-slider{
      padding-left: 50px;
      padding-right: 10px;
    }
    /deep/.el-color-picker{
      width: 210px;
      .el-color-picker__trigger{
        width: 100%;
      }
    }
  }
}


/deep/.x6-widget-stencil{
  width: 220px;
}
/deep/.x6-widget-stencil{
  border-right: 1px solid lightgray;
}
/deep/.x6-widget-stencil-title,/deep/.x6-widget-stencil-group-title{
  text-align: center;
}
</style>
